package com.miyu.system.service.sys.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.miyu.common.dao.commonDAO.book.BookRuleSetDao;
import com.miyu.common.pojo.book.BookPagePJ;
import com.miyu.common.pojo.book.BookRuleSet;
import com.miyu.common.service.book.BookCommonService;
import com.miyu.system.dao.sys.SysBookDao;
import com.miyu.system.dao.sys.SysBookRuleSetDao;
import com.miyu.system.service.sys.SysBookService;
import com.miyu.system.utils.bookUtils.BookCommutils;
import lombok.SneakyThrows;
import org.apache.commons.lang.StringUtils;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * sys书服务impl
 * 后端 book处理公共类
 *
 * @author longmy
 * @date 2022/02/25
 */
@Service
public class SysBookServiceImpl implements SysBookService {

    @Resource
    private SysBookDao sbd;
    @Resource
    private SysBookRuleSetDao bookRuleDao;
    @Autowired
    private BookCommonService bookCommonService;
    @Resource
    private BookRuleSetDao bookRuleSetDao;


    /**
     * 书籍主数据查询
     * @param param
     * @return
     */
    @Override
    public JSONArray queryBook(JSONObject param) {
        JSONArray rs = new JSONArray();
        JSONArray rule = getQueryBookRule(param);
        StringBuffer sql = new StringBuffer();
        for (int i = 0; i < rule.size(); i++) {
            String bookTable = rule.getJSONObject(i).getString("ruleBookList");
            sql.append("select book_id,rule_id,book_source,book_name,book_chapter_source,book_author,book_kind,book_state,book_cover,book_duce,book_last_chapter,");
            sql.append(" book_last_chapter_url,book_last_chapter_date,book_date");
            sql.append(" from ").append(bookTable);
            if(param.containsKey("search")) {
                if(StringUtils.isNotBlank(param.getString("search"))) {
                    sql.append(" where book_name like '%").append(param.getString("search")).append("%' or book_author like '%")
                            .append(param.getString("search")).append("%'");
                }
            }
            rs = this.sbd.queryJSONArrayBySql(sql.toString());
        }
        return rs;
    }

    /**
     *
     * 书籍明细数据查询(数据库查询)
     * @param param
     * @return
     */
    @Override
    public JSONArray sysQueryBoookDetail(JSONObject param) {
        if(!param.containsKey("bookId")){
            return null;
        }
        JSONArray rs = new JSONArray();
        String tableId = param.getString("bookChapterSource");
        String bookId = param.getString("bookId");
        StringBuffer sql = new StringBuffer();
        sql.append(" select chapter_id,book_id,chapter_source,chapter_num,chapter_name,chapter_context from ").append(tableId);
        sql.append(" where book_id='").append(bookId).append("'");
        sql.append(" order by chapter_num ");

        rs = this.sbd.queryJSONArrayBySql(sql.toString());
        return rs;
    }
    /**
     * 规则查询
     * @param param
     * @return
     */
//    @Cacheable(cacheNames = {"bookRuleSet"} )

    @Override
    public List<BookRuleSet> queryBookRuleSet(JSONObject param) {
        StringBuffer sql = new StringBuffer();
        String ruleName ="ruleName";
        sql.append(" from BookRuleSet    ");
        if (param.containsKey(ruleName)&&param.getString(ruleName).length()>0) {
            sql.append(" where ruleName like '%").append(param.getString(ruleName)).append("%'");
        }
        if(param.containsKey("isStop")) {
            sql.append(" where isStop = '").append(param.getString("isStop") ).append("'");
        }
            List<BookRuleSet> ruleSet = bookRuleDao.queryListByHql( sql.toString() );

        return ruleSet;
    }

    /**
     * 规则保存
     * @param param
     * @return
     */
    @Override
    @CacheEvict(cacheNames = "bookRuleSet" ,allEntries = true)
    public JSONObject saveBookRuleSet(JSONObject param) {

        String ruleSet = param.getString("ruleSet");
        System.out.println(param.getJSONObject("rlueSet").toJSONString());
        StringBuffer sql = new StringBuffer();
        boolean isUpdate=false;
        String ruleId="";
        if(param.containsKey("ruleId")){
            //更新数据
             ruleId=param.getString("ruleId");
            sql.append(" update book_rule_set set ");
            sql.append(" rule_name='").append(param.getString("ruleName")).append("',");
            sql.append(" root_source='").append(param.getString("rootSource")).append("',");
            sql.append(" root_search='").append(param.getString("rootSearch")).append("',");
            sql.append(" rule_set='").append(param.getJSONObject("rlueSet").toJSONString()).append("'");
            sql.append(" where rule_id='").append(ruleId).append("'");
        }else{
            //新增
            //随机生成主键
            isUpdate=true;
            ruleId= BookCommutils.getUUID();
            sql.append(" insert into book_rule_set ( rule_id,rule_name,root_source,root_search,root_type,rule_book_list,rule_chapter_list,is_stop,rule_set)");
            sql.append(" values (");
            sql.append("'").append(ruleId).append("',");
            sql.append("'").append(param.getString("ruleName")).append("',");
            sql.append("'").append(param.getString("rootSource")).append("',");
            sql.append("'").append(param.getString("rootSearch")).append("',");
            sql.append("'").append(param.getString("rootType")).append("',");
            sql.append("'").append("book_"+ruleId).append("',");
            sql.append("'").append("chapter_"+ruleId).append("',");
            sql.append("'0',");
            sql.append("'").append(param.getJSONObject("rlueSet").toJSONString()).append("')");
      
        }
        try {
            sbd.doExecute(sql.toString());
            if(isUpdate){
                createtable(ruleId);
            }
        }catch (Exception e){

        }
        JSONObject json = new JSONObject();
        json.put("code",0);
        json.put("msg","操作成功");
        return json;
    }

    /**
     * 删除规则
     * @param params
     * @return
     */
    @Override
    @CacheEvict(cacheNames = "bookRuleSet" ,allEntries = true)
    public JSONObject delBookRuleSet(JSONArray params) {
        for (int i = 0; i < params.size(); i++) {
            JSONObject jo = params.getJSONObject(i);
            deleteBookRule(jo);
        }
        JSONObject json = new JSONObject();
        json.put("code",0);
        json.put("msg","操作成功");
        return json;
    }

    /**
     * 规则校验取值
     * @param params
     * @return
     */
    @Override
    public JSONObject checkBookRule(JSONObject params) {
            JSONObject rs = new JSONObject();
            BookPagePJ pj = new BookPagePJ();
            String key = "checkRule";
            pj.setRuleId(params.getString("ruleId"));
            pj.setUrl(params.getString("url"));
            pj.setRuleStr(params.getString("ruleStr"));
            pj.setKey(key);
            JSONObject ps =  bookCommonService.BookPageJX(pj);
        System.out.println(ps);
            return ps;
    }

    /**
     * 删除本规则
     *
     * @param jo
     */
    public void deleteBookRule(JSONObject jo){
        String ruleId = jo.getString("ruleId");
        String bookList = jo.getString("ruleBookList");
        String chapterList = jo.getString("ruleChapterList");
        bookRuleDao.deleteById(ruleId);
        StringBuffer sql = new StringBuffer();
        //删除书籍主表
        sql.append("drop table ").append(bookList);
        sbd.doExecute(sql.toString());
        //所有章节分表
        String[] chTable = BookCommutils.chTable();
        for (int i = 0; i <chTable.length ; i++) {
            String tableId = chapterList+"_"+chTable[i];
            sql.setLength(0);
            if(checkTableExists(tableId)){
                sql.append("drop table ").append(tableId);
                sbd.doExecute(sql.toString());
            }
        }
    }


    private void createtable(String ruleId) {
        {
            String ruleBookList = "book_"+ruleId;
            String ruleChapterList = "chapter_"+ruleId;
            StringBuffer sql = new StringBuffer();
            boolean isMysql = BookCommutils.IsMysql();
            if (isMysql) {
                //判断吧表是否存在
                if (!checkTableExists(ruleBookList)) {
                    sql.append(" create table ").append(ruleBookList).append(" (");
                    sql.append(" book_id varchar (32) COMMENT '书籍列表主键' ,");
                    sql.append(" rule_id varchar (32) COMMENT '规则来源' ,");
                    sql.append(" book_source varchar(100) DEFAULT NULL COMMENT '书籍来源',");
                    sql.append(" book_name varchar(100) DEFAULT NULL COMMENT '数据名称',");
                    sql.append(" book_chapter_source varchar(100) DEFAULT NULL COMMENT '章节表',");
                    sql.append(" book_author varchar(50) DEFAULT NULL COMMENT '作者',");
                    sql.append(" book_kind varchar(50) DEFAULT NULL COMMENT '类别', ");
                    sql.append(" book_state varchar(20) DEFAULT NULL COMMENT '状态', ");
                    sql.append(" book_cover varchar(100) DEFAULT NULL COMMENT '图片',");
                    sql.append(" book_duce varchar(500) DEFAULT NULL COMMENT '简介',");
                    sql.append(" book_last_chapter varchar(100) DEFAULT NULL COMMENT '最新章节名称',");
                    sql.append(" book_last_chapter_url varchar(100) DEFAULT NULL COMMENT '最新章节链接',");
                    sql.append(" book_last_chapter_date varchar(20) DEFAULT NULL   COMMENT '最后更新日期',");
                    sql.append(" book_date   timestamp not null default current_timestamp COMMENT '操作时间',");
                    sql.append(" PRIMARY KEY (book_id) ");
                    sql.append("    ,INDEX book_ (book_name, book_author)   ");
                    sql.append(") ENGINE=InnoDB DEFAULT CHARSET=utf8 ");
                    sbd.doExecute(sql.toString());

                }
                if (!checkTableExists(ruleChapterList)) {
                    String[] chTable = BookCommutils.chTable();
                    for (int i = 0; i < chTable.length; i++) {
                        sql.setLength(0);
                        sql.append(" create table ").append(ruleChapterList).append("_").append(chTable[i]).append(" ( ");
                        sql.append("  chapter_id varchar(32) NOT NULL COMMENT '章节主键',");
                        sql.append(" book_id varchar(32) DEFAULT NULL COMMENT '书籍明细主键',");
                        sql.append(" chapter_source varchar(255) DEFAULT NULL COMMENT '章节来源',");
                        sql.append("  chapter_num int(8) DEFAULT NULL COMMENT '序列号', ");
                        sql.append(" chapter_name varchar(100) DEFAULT NULL COMMENT '章节名称',");
                        sql.append(" chapter_context mediumtext COMMENT '章节内容',");
                        sql.append(" PRIMARY KEY (chapter_id) ");
                        sql.append("    ,INDEX chapter_ (book_id, chapter_num asc )   ");
                        sql.append(") ENGINE=InnoDB DEFAULT CHARSET=utf8 ");
                        sbd.doExecute(sql.toString());
                    }
                }

            } else {
                //判断吧表是否存在
                if (!checkTableExists(ruleBookList)) {
                    sql.append(" create table ").append(ruleBookList).append(" (");
                    sql.append(" book_id varchar (32) primary key not null ,");
                    sql.append(" rule_id varchar (32)  ,");
                    sql.append(" book_source varchar(100) ,");
                    sql.append(" book_name varchar(100) ,");
                    sql.append(" book_chapter_source varchar(100) ,");
                    sql.append(" book_author varchar(50) ,");
                    sql.append(" book_kind varchar(50) , ");
                    sql.append(" book_state varchar(20) , ");
                    sql.append(" book_cover varchar(100) ,");
                    sql.append(" book_duce varchar(1500) ,");
                    sql.append(" book_last_chapter varchar(100) ,");
                    sql.append(" book_last_chapter_url varchar(100) ,");
                    sql.append(" book_last_chapter_date varchar(20) ,");
                    sql.append(" book_date  DATE not null default getdate()  ");
                    sql.append(")  ");
                    sbd.doExecute(sql.toString());
                }
                if (!checkTableExists(ruleChapterList)) {
                    String[] chTable = BookCommutils.chTable();
                    for (int i = 0; i < chTable.length; i++) {
                        sql.setLength(0);
                        sql.append(" create table ").append(ruleChapterList).append("_").append(chTable[i]).append(" ( ");
                        sql.append("  chapter_id varchar(32) primary key not null,");
                        sql.append(" book_id varchar(32) ,");
                        sql.append(" chapter_source varchar(255) ,");
                        sql.append("  chapter_num int , ");
                        sql.append(" chapter_name varchar(150) ,");
                        sql.append(" chapter_context nvarchar(max)");
                        sql.append(") ");
                        sbd.doExecute(sql.toString());
                        sql.setLength(0);
                        sql.append("create index idex_chapter on ").append(ruleChapterList).append("_").append(chTable[i]).append("(book_id,chapter_num asc)");
                        System.out.println(sql);
                        sbd.doExecute(sql.toString());
                    }
                }
            }
        }
    }

    /**
     * 检测表是否存在
     * @param ruleBookList
     * @return
     */
    private boolean checkTableExists(String ruleBookList) {
        StringBuffer sql = new StringBuffer();
        sql.append(" select count(0) count  from information_schema.TABLES t where  t.TABLE_NAME ='").append(ruleBookList).append("'");
        JSONObject rs = sbd.queryJSONObjectBySql(sql.toString());
        return !rs.getString("count").equals("0");
    }

    private JSONArray getQueryBookRule(JSONObject param) {
        JSONArray rs = new JSONArray();
        StringBuffer sql = new StringBuffer();
        sql.append("select rule_id ruleId,rule_book_list ruleBookList from book_rule_set where is_stop = '0' ");
        if(param.containsKey("ruleId")){
            sql.append(" and rule_id = '").append(param.getString("ruleId")).append("'");
        }
        rs = sbd.queryJSONArrayBySql(sql.toString());
        return  rs;
    }

    /**
     * 书籍首页主搜索功能（爬虫）
     * @param param
     * @return
     */
    @Override
    public JSONArray searchBook(JSONObject param){
        JSONArray rs = new JSONArray();
        List<String> cond = new ArrayList<>();
        StringBuffer sql = new StringBuffer();
        sql.append(" from BookRuleSet where isStop = '0' ");
        if(param.containsKey("ruleId")){
            sql.append(" and ruleId = '").append(param.getString("ruleId")).append("'");
        }
        List<BookRuleSet>  bookRuleSet = bookRuleDao.queryListByHql(sql.toString());
        for ( BookRuleSet bookRule : bookRuleSet) {
            cond.add("bookSearch");
            BookPagePJ pj = new BookPagePJ();
            pj.setRuleId(bookRule.getRuleId());
            pj.setParam(param);
            pj.setCond(cond);
            pj.setKey("search");
            pj.setRemove(true);
            JSONObject pageJX =  bookCommonService.BookPageJX(pj);
            rs = pageJX.getJSONArray("data");
        }
        System.out.println(rs);
        return rs ;
    }

    /**
     * 明细数据查询（异常）
     * 需要参数
     * bookUrl
     * ruleId
     * @param param
     * @return
     */
    @Override
    public JSONObject querySearchBookDetail(JSONObject param){
        JSONObject rs = new JSONObject();
        List<String> cond = new ArrayList<>();
        cond.add("bookChapterList");
        BookPagePJ pj = new BookPagePJ();
        pj.setRuleId(param.getString("ruleId"));
        pj.setParam(param);
        pj.setUrl(param.getString("bookUrl"));
        pj.setCond(cond);
        pj.setKey("bookChapterList");
        rs =  bookCommonService.BookPageJX(pj).getJSONArray("data").getJSONObject(0);
        return rs ;
    }

    /**
     * 书籍明细查询（爬虫）
     * @param param
     * @return
     */
    @Override
    public JSONObject queryBookDetail(JSONObject param){
        /*必须有规则*/
        System.out.println(param);
        String ruleId = param.getString("ruleId");
        String bookUrl = param.getString("bookUrl");
        JSONObject bookDetail = bookCommonService.queryBookDetail(ruleId, bookUrl);
        return bookDetail ;
    }

    /**
     * 查询书章节（爬虫）
     *
     * @param param 参数
     * @return {@link JSONObject}
     */
    @Override
    public JSONObject queryBookChapter(JSONObject param) {
        String ruleId = param.getString("ruleId");
        String bookUrl = param.getString("bookUrl");
        JSONObject bookChapter= bookCommonService.queryBookChapter(ruleId, bookUrl);
        return bookChapter ;
    }

    /**
     * 查询阅读（爬虫）
     *
     * @param param 参数
     * @return {@link JSONObject}
     */

    @Override
    public JSONObject queryBookReader(JSONObject param){
        System.out.println(param);
        String url = "";
        if(param.containsKey("contextUrl")) {
            url=param.getString("contextUrl");
        } else {
            url=param.getString("chapterUrl");
        }
        String ruleId = param.getString("ruleId");
        param.put("url", url);
//        String bookUrl = url;
        JSONObject reader= bookCommonService.queryBookReader(param);
        return reader ;
    }

    @Override
    public JSONObject querySearchBook(JSONObject param) {
        String template = "{}爱{}，就像老鼠爱大米";
        String str = StrUtil.format(template, "我", "你"); //str -> 我爱你，就像老鼠爱大米

        JSONObject rs = bookCommonService.querySearchBook(param);
        return rs;
    }

    /**
     * 相关文件下载
     * @param param
     * @return
     */
    @Autowired
    private HttpServletRequest request;
    @Autowired
    private HttpServletResponse response;
    @SneakyThrows
    @Override
    public HttpServletResponse downloadFile(JSONObject param)  {
        System.out.println(param);

        String url = param.getString("url");
        String bookName = url.substring(url.lastIndexOf("/")+1,url.lastIndexOf("."))+url.substring(url.lastIndexOf("."));
        url=new String(url.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8);
        Connection.Response execute = null;
        execute = Jsoup.connect(url).timeout(100000).maxBodySize(0).ignoreContentType(true).execute();
        response.reset();
        response.addHeader("Content-Disposition", "attachment;filename=" + new String(bookName.getBytes(StandardCharsets.UTF_8),"ISO8859-1"));
        response.setContentType("application/octet-stream");
        OutputStream out=  response.getOutputStream();
        out.write(execute.bodyAsBytes());
        out.close();


        return null;
    }

    /**
     * 书籍采集功能
     *
     * @param param 参数
     * @return {@link JSONObject}
     */
    @Override
    public JSONObject collectBook(JSONObject param) {
        JSONObject rs = new JSONObject();
        String ruleId = param.getString("ruleId");
        int start = param.getInteger("start");
        int end = param.getInteger("end");

        BookRuleSet bookRule = bookCommonService.getBookRuleById(ruleId);

        JSONObject jsonObject = new JSONObject();
        for(int i=start;i<=end;i++){
                List<String> cond = new ArrayList<>();
                String  url = param.getString("url").replace("*",String.valueOf(i));

                param.put("url",url);
                param.put("ruleId",ruleId);
                jsonObject = bookCommonService.collectBook(param);

            }

            rs.put("code", "1");
            rs.put("msg", jsonObject);
            return jsonObject;
    }
}
